package com.yzion.baselib.http.progress

import android.os.Handler
import android.os.Looper
import okhttp3.Interceptor
import okhttp3.Request
import okhttp3.Response
import java.lang.ref.WeakReference
import java.util.*

/**
 * 进度回调帮助类，主要用于下载文件时监听下载进度.
 * 常见用法参考如下
 */
/*
private fun download() {
    val client = OkHttpClient.Builder()
        .addNetworkInterceptor(ProgressHelper.get().interceptor)
        .build()
    val request = Request.Builder()
        .url(upgradeBean.downloadUrl!!)
        .get()
        .build()
    val call = client.newCall(request)
    BaseManager.service.launch {
        try {
            val response = call.execute()
            val inputStream = response.body!!.byteStream()
            val file = File(appFilePath)
            FileIOUtils.writeFileFromIS(file, inputStream)
            withContext(Dispatchers.Main) {
                downloadFinished()
            }
        } catch (e: Exception) {
            e.printStackTrace()
        }
    }
    ProgressHelper.get()
        .addResponseListener(upgradeBean.downloadUrl!!, object : ProgressListener {
            override fun onProgress(soFarBytes: Long, totalBytes: Long) {
                progressBar.progress =
                    ((soFarBytes.toFloat() / totalBytes.toFloat()) * 100f).toInt()
                if (soFarBytes == totalBytes) {
                    progressBar.progress = 100
                }
            }

            override fun onError(throwable: Throwable?) {
                throwable?.let { showErrorMsg(it) }
            }

        })
}
 */
class ProgressHelper private constructor() {

    private val requestListenerMap: MutableMap<String, MutableSet<WeakReference<ProgressListener>>?> =
        WeakHashMap()
    private val responseListenerMap: MutableMap<String, MutableSet<WeakReference<ProgressListener>>?> =
        WeakHashMap()

    val interceptor: Interceptor

    /**
     * 添加请求进度回调监听
     */
    fun addRequestListener(url: String, listener: ProgressListener) {
        var listeners: MutableSet<WeakReference<ProgressListener>>?
        synchronized(ProgressHelper::class.java) {
            listeners = requestListenerMap[url]
            if (listeners == null) {
                listeners = HashSet()
                requestListenerMap[url] = listeners
            }
            listeners!!.add(WeakReference(listener))
        }
    }

    /**
     * 添加响应进度回调监听
     */
    fun addResponseListener(url: String?, listener: ProgressListener?) {
        if (url == null || listener == null) return
        var listeners: MutableSet<WeakReference<ProgressListener>>?
        synchronized(ProgressHelper::class.java) {
            listeners = responseListenerMap[url]
            if (listeners == null) {
                listeners = HashSet()
                responseListenerMap[url] = listeners
            }
            listeners!!.add(WeakReference(listener))
        }
    }

    /**
     * 移除请求进度回调监听
     */
    fun delRequestListener(url: String?, listener: ProgressListener?) {
        if (requestListenerMap.isEmpty()) return
        if (url == null) {
            if (listener != null) {
                for (key in requestListenerMap.keys) {
                    delReference(requestListenerMap[key], listener)
                }
            }
        } else {
            if (listener != null) {
                delReference(requestListenerMap[url], listener)
            } else {
                requestListenerMap.remove(url)
            }
        }
    }

    /**
     * 移除响应进度回调监听
     */
    fun delResponseListener(url: String?, listener: ProgressListener?) {
        if (responseListenerMap.isEmpty()) return
        if (url == null) {
            if (listener != null) {
                for (key in responseListenerMap.keys) {
                    delReference(responseListenerMap[key], listener)
                }
            }
        } else {
            if (listener != null) {
                delReference(responseListenerMap[url], listener)
            } else {
                responseListenerMap.remove(url)
            }
        }
    }

    /**
     * 清楚全部监听
     */
    fun clearAll() {
        requestListenerMap.clear()
        responseListenerMap.clear()
    }

    private fun wrapRequestBody(request: Request?): Request? {
        if (request?.body == null) return request
        val key = request.url.toString()
        if (requestListenerMap.containsKey(key)) {
            val listeners: Set<WeakReference<ProgressListener>> = requestListenerMap[key]!!
            return request.newBuilder()
                .method(request.method, ProgressRequestBody(request.body!!, listeners))
                .build()
        }
        return request
    }

    private fun wrapResponseBody(response: Response?): Response? {
        if (response?.body == null) return response
        val key = response.request.url.toString()
        if (responseListenerMap.containsKey(key)) {
            val listeners: Set<WeakReference<ProgressListener>> = responseListenerMap[key]!!
            return response.newBuilder()
                .body(ProgressResponseBody(response.body!!, listeners))
                .build()
        }
        return response
    }

    private fun delReference(
        references: MutableSet<WeakReference<ProgressListener>>?,
        listener: ProgressListener
    ) {
        if (references != null) {
            for (reference in references) {
                if (reference.get() != null && reference.get() === listener) {
                    references.remove(reference)
                }
            }
        }
    }

    private object Holder {
        val instance = ProgressHelper()
    }

    companion object {
        private val mainHandler = Handler(Looper.getMainLooper())
        fun get(): ProgressHelper {
            return Holder.instance
        }

        //分发进度状态事件
        fun dispatchProgressEvent(
            listeners: Set<WeakReference<ProgressListener>>?,
            soFarBytes: Long, totalBytes: Long
        ) {
            if (listeners != null) {
                for (reference in listeners) {
                    if (reference.get() != null) {
                        mainHandler.post {
                            reference.get()!!.onProgress(soFarBytes, totalBytes)
                        }
                    }
                }
            }
        }

        fun dispatchErrorEvent(
            listeners: Set<WeakReference<ProgressListener>>?,
            throwable: Throwable?
        ) {
            if (listeners != null) {
                for (reference in listeners) {
                    if (reference.get() != null) {
                        mainHandler.post { reference.get()!!.onError(throwable) }
                    }
                }
            }
        }
    }

    init {
        interceptor = Interceptor { chain: Interceptor.Chain ->
            wrapResponseBody(
                chain.proceed(
                    wrapRequestBody(chain.request())!!
                )
            )!!
        }
    }
}